home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Deutsche Edition 1
/
Deutsche Edition 1.iso
/
amok
/
001-010
/
amok05
/
superlists1.2
/
superlist.doc
< prev
next >
Wrap
Text File
|
1993-11-04
|
19KB
|
354 lines
Dokumentation zu SuperLists Version 1.2
Autor: Nicolas Benezan, Postwiesenstr. 2, D7000 Stuttgart 60
Einleitung
----------
Jeder kennt die Windows mit den Proportionalgadgets im rechten und
unteren Rand. Man sieht sie auf der Workbench, in Textverarbeitungs-
programmen und -Editoren oder in Requestern bei der Auswahl einer zu
ladenden Datei (zB. bei Dpaint). Diese Windows oder Requester ermöglichen
eine komfortable Benutzung, weil man sich mit Hilfe der Scrollgadgets
jeden beliebigen Teil der Gesammtdaten anzeigen lassen kann, und man an
den Proportionalgadgets gleichzeitig ablesen kann, wie groß der
Ausschnitt ist, den man gerade sieht. Besonders nützlich ist dies, wenn
die Windowgröße veränderlich ist, und bei kleinem Window nicht mehr alle
Daten hineinpassen (siehe Workbench-Windows) oder, wie bei einem
Textverarbeitungsprogramm, eine Textseite von vorneherein viel größer als
eine Bildschirmseite ist.
Wer selbst Programme schreibt, schreckt vielleicht vor der komplizierten
Programmierung solcher Scrollwindows zurück und verwendet lieber eine
einfacher zu programmierende Technik. Hierunter leidet die
Benutzerfreundlichkeit des Programms, und das muß wirklich nicht sein,
vor allem seit es "Superlists" gibt. Mit diesem Modul beschränkt sich der
Aufwand auf die Initialisierung und Verwaltung der Daten. Wie diese
angezeigt werden, wie gescrollt wird ist Sache von "SuperLists".
Neu: Version 1.2
----------------
Version 1.0 hatte gegenüber dieser Version folgende Nachteile: es
verwendete immer das Modul Heap für seine Speicherverwaltung, eigene
Speicherverwaltungsroutinen einzubauen war sehr stressig. Außerdem war
das alte SuperLists auf vertikal und horizontal scrollende Listen
beschränkt.
Bei der neuen Version kann auf Wunsch das horizontale Scrollgadget
weggelassen werden. Es ist nun auch möglich, mit Hilfe der
Prozedurvariablen AllocProc und DeallocProc eine eigene
Speicherverwaltung einzubinden.
Es haben sich auch einige Wanzen in der Version 1.0 eingeschlichen, die
jetzt korrigiert sind:
-RemoveEntry und InsertEntry haben die Liste nicht korrekt angezeigt, es
mußte jedesmal RefreshList aufgerufen werden
-Hide bei obigen Prozeduren funktionierte nicht
-ClickRow berechnete die Zeile falsch
So wird's gemacht
-----------------
Bevor man eine SuperList erzeugt, sollte man sich über folgendes im
Klaren sein:
* In welchem Window(-rastport) oder Requester(-rastport) soll
die Liste angezeigt werden
* Welche Hintergrundfarbe hat die Liste
* Wie sollen die Proportionalgadgets für vertikales und (falls
erwünscht) horizontales Srolling aussehen
* Wo und wie groß soll die Liste im Window (Requester) angezeigt
werden
* Welche Daten hat der zu dem verwendeten RastPort gehörige Zeichensatz
(Achtung, es darf keine Proportionalschrift sein)
* Welcher Ausschnitt soll voreinstellungsgemäß angezeigt werden
Neu: Bei der Version 1.2 kann nun auch gewählt werden, ob die Liste nur
vertikal oder vertikal und horizontal gescrollt werden soll.
Falls jemand das Programm so verändern will, daß es auch Grafik (wie zB.
die Icons in den Workbench-Windows) beherrscht, bin ich gerne bereit,
eventuelle Fragen zu beantworten.
Erzeugen der Scrollgadgets
--------------------------
Jede SuperList benötigt ein oder zwei Proportionalgadgets, eines für das
vertikale Scrolling und optional ein zweites für die horizontale
Richtung. Diese Gadgets müssen erzeugt werden, bevor die Liste
initialisiert wird. Es wird hier auf eine Beschreibung, wie dies
geschieht, verzichtet. Dies kann man zB. im "Intuition Reference Manual"
nachlesen.
Initialisieren der Liste
------------------------
Eine SuperList besteht aus einem Listenkopf (SuperList-RECORD) und null
oder mehreren Einträgen (Entry-RECORDs). Der Listenkopf enthält
Parameter, die das Aussehen der Liste beschreiben, und solche, die vom
SuperList-Modul zur Verwaltung der Liste benötigt werden, sowie eine
Exec.List zur Verwaltung der Einträge. Ein Eintrag enthält einen
Exec.Node zur verknüpfung der Einträge untereinander und den eigentlichen
Text (in Entry.node.name) sowie Parameter, die das Aussehen des Textes
beschreiben (Farbe, DrawMode).
Bevor die Liste das erste mal verwendet werden kann, müssen folgende
Paramter in der SuperList-Struktur initialisiert werden:
* rastPort - Zeiger auf den RastPort des Windows oder Requesters, in
dem die Liste angezeigt werden soll.
* backPen - Hintergrundfarbe der Liste
* propY - Zeiger auf das Proportionalgadget für vertikales Scrolling
* propX - Zeiger auf das Gadget für horizontales Scrolling
falls dies nicht erwünscht ist, sollte PropX auf NIL gesetzt werden
* leftEdge - linker Rand der Listenanzeigefläche relativ zum linken
Rand des Windows oder Requesters (Einheit: Pixel)
* topEdge - oberer Rand relativ zum Rand des Windows/Requesters
* width - Breite der Anzeigefläche (Einheit: Pixel), muß mindestens so
groß wie FontXsize+1 sein (s. unten)
* height - Höhe der Anzeigefläche, muß mindestens FontYsize sein
* FontXsize - Breite eines Zeichens in Pixel (kein Proportional-
schriftsatz!)
* FontYsize - Höhe einer Textzeile in Pixel (muß nicht unbedingt mit
der Höhe eines Zeichens übereinstimmen, wenn zB. zusätzlicher
Zeilenabstand erwünscht ist)
* FontBaseLine - besagt, auf welcher Höhe die Grundlinie der Zeichen
innerhalb einer Zeile liegen soll, sollte ungefähr gleich dem
baseLine-Paramter des Fonts gesetzt werden
* dispRow - Nummer des ersten Eintrags (Zeile) des zuerst
anzuzeigenden Ausschnitts (0 ist der erste Eintrag)
* dispColumn - Nummer der ersten Spalte des Ausschnitts (0 zeigt ab
der ersten Spalte) ist kein horizontales Scrolling vorgesehen, sollte
dieses Feld immer 0 sein
* Die Exec.List muß initialisiert werden. Dies geschieht am besten mit
ExecSupport.NewList(ADR(SuperList.list); .
Alle anderen Felder sollten nie verändert werden, sie dienen der internen
Verwaltung. Es ist aber vielleich manchmal interessant, sie zu lesen,
deshalb hier ihre Bedeutungen:
* rows - Anzahl der vorhandenen Einträge (Zeilen)
* columns - Anzahl der Spalten = Länge des längsten Eintrags (in
Zeichen, nicht in Pixel), nur bei eingeschltetem horizontalem
Scrolling definiert
* topEntry - Zeiger auf den Node des obersten angezeigten Eintrags
* bottomEntry - Zeiger auf den untersten angezeigten Eintrag
(Vorsicht: Falls keine Einträge vorhanden sind, müssen top- und
bottomEntry nicht unbedingt NIL sein. Diese Zeiger sollten möglichst
nicht für eigene Zwecke verwendet werden.)
* effWidth - Breite der Anzeigefläche in Zeichen (nicht in Pixel)
* effHeight - Höhe in Zeichen
Nachdem alles ordnungsgemäß initialisiert ist, wird RethinkList(
SuperListPtr, NewList) aufgerufen, wobei SuperListPtr ein Zeiger auf den
SuperList-RECORD und NewList eine von SuperLists exportierte Konstante
ist. Um den aktuellen Ausschnitt der Liste anzuzeigen, verwendet man
RefreshList(SuperListPtr). Man kann die Liste jetzt mit den Prozeduren
ScrollList, InsertEntry, RemoveEntry, GetEntry, SetProp, GetProp,
ClickRow, MakeEntry, RedrawEntry, RethinkList und RefreshList bearbeiten.
RefreshList
-----------
Diese Prozedur wird benötigt, um die Paramter zur interenen Verwaltung im
Listenkopf neu zu berechnen. Normalerweise werden diese beim Aufruf von
Prozeduren wie zB. InsertEntry automatisch aktualisiert. Es ist jedoch
manchmal nötig, einige Parameter "von Hand" zu ändern, wenn zB. der
Benutzer die Windowgröße verändert hat, und sich damit auch die
Anzeigefläche der Liste verändert. Um das SuperLists-Modul davon in
Kenntnis zu setzen, daß Parameter verändert wurden, sodaß es seine
internen Parameter neu berechnen kann, wird RethinkList verwendet. Der
Parameter New (newList oder oldList) besagt, inwieweit die
Listenparameter rekonstruiert werden müssen. RethinkList(...,oldList)
wird verwendet, wenn die Veränderung nur die Anzeigefläche betrifft (zB.
Höhe, Breite, Zeichensatz usw.). Die Ausführungszeit ist im Gegensatz zu
RethinkList(...,newList) relativ kurz. Bei letzterem wird nämlich die
ganze Liste der Einträge durchgegangen und Zeilen und Spalten werden neu
gezählt. Dies ist notwendig, wenn die Einträge mit anderen Prozeduren als
die von SuperLists bearbeitet wurden, sodaß sich die Texte der Einträge
verändert haben, oder Eiträge entfernt oder hinzugefügt wurden. Ein
weiterer Fall ist das Erzeugen einer neuen Liste (siehe oben) oder ein
Spezialfall von RemoveEntry (siehe dort). Wegen der besonders bei sehr
großen Listen langen Ausführungszeit sollte RethinkList(...,newList)
möglichst vermieden werden. Um einen einzelnen Eintrag abzuändern, ist es
besser, ihn mit RemoveEntry zu entfernen und nach der Änderung mit
InsertEntry wieder einzufügen.
Folgende Parameter dürfen verändert werden, ohne daß RethinkList benötigt
wird:
SuperList.backPen, SuperList.FontBaseLine, Entry.frontPen, Entry.back-
Pen, Entry.drawMode, Entry.userFlags, Entry.userData .
Achtung: Wenn Parameter (außer den oben genannten) einer SuperList-
Struktur "von Hand", also nicht über SuperLists-Prozeduren, verändert
werden, so darf keine andere SuperLists-Prozedur aufgerufen werden, bevor
nicht RethinkList ausgeführt wurde. Die Prozedur findet sonst ungültige
Werte vor, was zu einer chaotischen Anzeige und schlimmstenfalls sogar
zum Systemabsturz führen kann. Falls von mehreren Tasks aus auf eine
Liste zugegriffen wird, muß das Programmstück von der
Parameterveränderung bis RethinkList im Forbidden-Status ablaufen.
RethinkList korrigiert soweit als möglich ungültige Werte. Wenn zB. der
aktuelle Anzeigeauschnitt über das Ende der Liste hinaus positioniert
wurde, so wird der Ausschnitt auf die tiefstmögliche Position gesetzt.
Diese Gutmütigkeit hat aber ihre Grenzen. So sollte man zB. keine Zeiger
der Exec.List "verbiegen" oder eine negative Anzeigenbreite einstellen,
weil solche "Scherze" meist unvorhersehbare Folgen haben.
RefreshList
-----------
Wie schon der Name sagt, dient diese Prozedur dem Auffrischen, dh. dem
Neu-Anzeigen, des sichtbaren Listenausschnitts. Dies wird in drei Fällen
benötigt:
* wenn die Liste zum ersten mal angezeigt werden soll,
* wenn sich die Liste in einem SimpleRefresh-Window befindet und man
eine Message vom Typ "refreshWindow" erhält oder
* wenn sich die Größe der Anzeigefläche verändert hat. Es ist auch
dann ein Auffrischen erforderlich, wenn die Fläche kleiner geworden
ist.
Im Fall 1 und 3 ist auch noch zusätzlich SetProp() erforderlich (siehe
dort).
RedrawEntry
-----------
Zeigt einen Eintrag (Zeile) neu an, sofern sich dieser im gerade
sichtbaren Ausschnitt befindet. Dies ist notwendig, wenn zB. der Text,
die Farbe oder der DrawModus dieses Eintrags verändert wurde. Falls sich
die Länge des Texts verändert hat muß außerdem RethinkList() aufgerufen
werden (siehe oben). Es ist dabei möglich, vorher einen alternativen
Zeichensatz (zB. kursiv) zu setzen (mit Graphics.Set- Font() ), um diesen
Eintrag besonders hervorzuheben. Dieser muß (!) aber die gleiche
Zeichengröße wie der vorher verwendete haben (FontXsize, FontYsize).
ScrollList
----------
wird verwendet, um die Liste Zeichenweise in eine beliebige Richtung zu
scrollen. Dies wird besonders bei Texteditoren benötigt, oder wenn die
beiden Proportionalscrollgadgets noch mit je zwei Boolgadgets kombiniert
sind (siehe zB. die kleinen Pfeile in den Ecken der Workbench-Windows).
Das Scrolling läuft relativ schnell (weil blitterunterstützt) ab, und es
wird nur der beim Verschieben der BitPlane-Daten freigelegte Abschnitt
neu gezeichnet. Es wird damit möglich, Texteditoren zu bauen, bei denen
mann nicht ewig warten muß, wenn man sich mit dem Cursor über den
Windowrand hinausbewegt hat (sowas soll's auch geben!).
Es ist nicht möglich, über das Ende oder vor den Anfang der Liste zu
scrollen. Dies wird automatisch erkannt und abgefangen.
"Dir" gibt die Richtung an, mit der sich das imaginäre Fenster über die
Liste bewegt. "Left" bedeutet also, die sichtbaren Daten werden
eigentlich rechtsverschoben, links wird ein Zeichen mehr sichtbar, rechts
verschwindet eins.
MakeEntry
---------
Bevor irgendetwas angezeigt oder gescrollt werden kann, müssen erst
einmal Einträge in der Liste vorhanden sein. Meistens werden diese
dynamisch alloziert, was am besten mit der Prozedur MakeEntry geschieht.
Es wird ein Zeiger auf einen auf Null endenden String, Vorder- und
Hinergrundfarbe und der gewünschte DrawModus übergeben. MakeEntry
alloziert dann Speicher für den Entry-RECORD und den Text (einschließlich
abschließender Null), kopiert den Text in den neuen Speicher und
initialisiert den Entry-RECORD. Dabei wird die Länge des Textes (ohne
Null) im Feld node.pri abgelegt. Will man Einträge anders als mit
MakeEntry erzeugen, so ist es wichtig, dies ebenfalls zu tun, da die
Länge für die weitere Verwaltung der Liste nötig ist.
Die Felder userFlags und userData werden nicht benutzt und können vom
Programmierer für beliebige Zwecke verwendet werden.
Ist nicht mehr genügend freier Speicher vorhanden, wird NIL
zurückgegeben.
InsertEntry
-----------
wird verwendet, um an der Stelle (Zeile) "Row" den Eintrag "Entry" in die
Liste einzufügen. der Parameter "hidden" besagt, ob der Einfügevorgang
sichtbar (s. Konstante "showIt") oder unsichtbar (hideIt) erfolgen soll.
Dies kann wünschenswert sein, wenn mehere Einträge auf einmal eingefügt
werden sollen. Es wäre umständlich und würde eventuell zu viel Zeit
benötigen, nach jeder eingefügten Zeile die Liste neu anzuzeigen.
Stattdessen erfolgt das einfügen der Zeilen unsichtbar. Erst die letzte
Zeile wird sichtbar eingefügt, womit die gesammte Veränderung sichtbar
wird. Einfügen außerhalb des gerade sichtbaren Ausschnitts der Liste
erfolgt natürlich immer unsichtbar, unabhängig vom Parameter "hidden".
Wird bei "Row" ein negativer Wert oder ein Wert, der hinter dem Ende der
Liste liegt, angegeben, dann wird am Ende der Liste angehängt.
RemoveEntry
-----------
Diese Prozedur entfernt einen Eintrag aus der Liste. "Row" bezeichnet die
Nummer des zu ertfernenden Eintrags (Zeile). Der Parameter "hidden" wird
wie bei InsertEntry gehandhabt. Mit dem Parameter "mustRethink" hat es
folgendes auf sich:
Wird der längste Eintrag aus der Liste entfernt, ändert sich die
Gesammtbreite der Liste, und diese muß mit RethinkList neu bestimmt
werden. Dies wird nicht automatisch durchgeführt, da es Fälle gibt, in
denen das Aufrufende Programm besser weiß, wann dies nötig ist und wann
nicht. Es ist zB. denkbar, daß bei einem Textverarbeitungs- programm alle
Zeilen einer Seite sowieso die gleiche maximale Länge haben (DIN A4), und
es deshalb Performance-Verschwendung wäre, jedesmal RethinkList
durchzuführen. Wird also bei RemoveEntry festgestellt, daß der entfernte
Eintrag der Längste war, dann wird "mustRethink" TRUE, ansonsten bleibt
es unverändert. Das bedeutet zwar, daß dieses Flag vor dem (ersten von
mehreren) Aufruf(en) gelöscht werden muß, ermöglicht aber eine Art Oder-
Verknüpfung bei mehreren RemoveEntry-Aufrufen hintereinander.
GetEntry
--------
ermöglicht es, die Adresse des Entrys mit der Numer "Row" zu suchen.
Falls der Eintrag vorhanden ist, wird ein Zeiger auf ihn zurückgegeben,
ansonsten ist das Ergebnis NIL.
Es wird darauf hingewiesen, daß diese Suche unter Umständen lange dauern
kann, falls der gesuchte Eintrag nicht im sichtbaren Ausschnitt liegt
(dort wird zuerst gesucht). Besonders bei sehr großen Listen (deutlich
mehr als 1000 Einträge) kann es länger dauern, weil dann die gesammte
Liste durchgegangen wird. Dies gilt im übrigen auch für Insert- und
RemoveEntry, die intern auch diese Prozedur verwenden.
Ich glaube aber, daß dies kein wesentliche Nachteil ist, weil Superlists
wohl meistens für weniger lange Listen verwendet werden wird.
ClickRow
--------
Mit dieser Prozedur kann festgestellt werden, welchen Eintrag der
Benutzer gemeint hat, als er einen Punkt im Window der Liste angeklickt
hat. Es werden die Koordinaten des Zeigers relativ zum Nullpunkt des
RastPorts (des Windows oder Requesters) übergeben. Das Ergebnis ist dann
die Nummer des Eintrags oder -1, falls sich der Mauszeiger außerhalb des
Anzeigebereichs der Liste befand.
GetProp
-------
Wenn festgestellt worden ist, daß der Benutzer eines der
Proportionalgadgets bewegt hat, muß die Stellung der Gadgets ausgelesen
und der gewünschte Ausschnitt der Liste dargestellt werden. GetProp
erledigt ersteres, RefreshList letzteres. Die beiden Prozeduren wurden
nicht zu einer zusammengefaßt, weil es möglich ist, daß der Programmierer
zwischen beiden noch einiges ausführen möchte. Bei der Verwendung von
Proportionalgadgets können nämlich Rundungsfehler auftreten, die sich
darin äußern, daß beim Vor- oder Zurückblättern um eine Seite (Anklicken
der Fläche neben dem Knob im Container) eine Zeile irrtümlicherweise
übersprungen wird. So ist es möglich, vor RefreshList die Parameter des
List-RECORDS entsprechend zu korrigieren (RethinkList nicht vergessen).
Wird darauf verzichtet, ist RethinkList nicht notwendig, dh. RefreshList
kann direkt nach GetProp aufgerufen werden.
SetProp
-------
Hat sich die Größe der Liste oder des Windows verändert, oder wurde mit
ScrollList gearbeitet, dann müssen Stellung (Pot) und Größe (Body) der
(Auto-)Knobs der Proportionalgadgets aktualisiert werden. Dies kann mit
der Prozedur SetProp geschehen, die die Pot- und Body-Variablen der
Gadgets entsprechend dem Verhältnis der sichtbaren Daten zu den
Gesammtdaten einstellt und danach Intuition.ModifyProp() aufruft. Sind
weniger Einträge vorhanden, als das Window hoch ist bzw. alle Einträge
kürzer sind als das Window breit ist, so werden die Body-Werte der
zugehörigen Gadgets auf das Maximum gestellt, dh. der Knob füllt den
ganzen Container.
AllocProc, DeallocProc
----------------------
Wie auch schon in IntuiStruct 1.3 (Amok #3) wurde jetzt auch in
SuperLists die Möglichkeit geschaffen, andere Speicherverwaltungs-
routinen als die von Heap zu installieren. Sie können jetzt die Vorteile
einer eigenen Speicherverwaltung nutzen, wie sie z.B. "MemSystem" (auch
auf dieser Amok-Diskette) bietet.
Die Prozedurvariablen AllocProc und DeallocProc müssen vor der Benutzung
von
* MakeEntry(...) oder
* RemoveEntry(...,deallocIt)
initialisiert werden. Beispiel:
SuperLists.AllocProc:=MemSystem.Allocate;
SuperLists.DeallocProc:=MemSystem.Deallocate;
oder
SuperLists.AllocProc:=Heap.Allocate;
SuperLists.DeallocProc:=Heap.Deallocate;
______________________
Viel Spaß !
Bene